#include<iostream>
#include<string.h>
#include <time.h> 
#include <typeinfo>
#include <vector>
#include <deque>
#include <list>
using namespace std;

class MyString {
public:
    static size_t DCtor;    //default-ctor
    static size_t Ctor;     //ctor
    static size_t CCtor;    //copy-ctor
    static size_t CAsgn;    //copy-assignment
    static size_t MCtor;    //move-ctor
    static size_t MAsgn;    //move-asgn
    static size_t Dtor;     //dtor

private:
    char* _data;
    size_t len;
    void init_data(const char* s) {
        _data = new char[len+1];
        memcpy(_data, s, len);
        _data[len] = '\0';
    }
public:
    //defaultctor
    MyString():_data(NULL),len(0){++DCtor;}

    //ctor
    MyString(const char* p):len(strlen(p)) {
        ++Ctor;
        init_data(p);
    }
    //copyctor
    MyString(const MyString& str): len(str.len) {
        ++CCtor;
        init_data(str._data);
    }
    //movector
    MyString(MyString&& str) noexcept: _data(str._data),len(str.len) {
        ++MCtor;
        str.len = 0;
        str._data = NULL; //★重要
    }
    //copy-assignment
    MyString& operator=(const MyString& str) {
        ++CAsgn;
        if(this != &str) {
            if(_data)
                delete _data;
            len = str.len;
            init_data(str._data);
        }
        else {

        }
        return *this;
    }
    MyString& operator= (MyString&& str) noexcept {
        ++MAsgn;
        if(this != &str) {
            if(_data) {
                delete _data;
            }
            len = str.len;
            _data = str._data;
            str.len = 0;
            str._data = NULL; //重要
        }
    }

    virtual ~MyString() {
        ++Dtor;
        if(_data) {
            delete _data;
        }
    }
    bool operator< (const MyString& rhs) const {
        return string(this->_data) < string(rhs._data); 
    }
    bool operator== (const MyString& rhs) const {
        return string(this->_data) == string(rhs._data);
    }

    char* get() const {
        return _data;
    }

};

class MyStrNoMove {
public:
    static size_t DCtor;    //default-ctor
    static size_t Ctor;     //ctor
    static size_t CCtor;    //copy-ctor
    static size_t CAsgn;    //copy-assignment
    static size_t MCtor;    //move-ctor
    static size_t MAsgn;    //move-asgn
    static size_t Dtor;     //dtor

private:
    char* _data;
    size_t len;
    void init_data(const char* s) {
        _data = new char[len+1];
        memcpy(_data, s, len);
        _data[len] = '\0';
    }
public:
    //defaultctor
    MyStrNoMove():_data(NULL),len(0){++DCtor;}
    //ctor
    MyStrNoMove(const char* p):len(strlen(p)) {
        ++Ctor;
        init_data(p);
    }
    //copyctor
    MyStrNoMove(const MyStrNoMove& str): len(str.len) {
        ++CCtor;
        init_data(str._data);
    }


    //copy-assignment
    MyStrNoMove& operator=(const MyStrNoMove& str) {
        ++CAsgn;
        if(this != &str) {
            if(_data)
                delete _data;
            len = str.len;
            init_data(str._data);
        }
        else {

        }
        return *this;
    }


    virtual ~MyStrNoMove() {
        ++Dtor;
        if(_data) {
            delete _data;
        }
    }
    bool operator< (const MyStrNoMove& rhs) const {
        return string(this->_data) < string(rhs._data); 
    }
    bool operator== (const MyStrNoMove& rhs) const {
        return string(this->_data) == string(rhs._data);
    }

    char* get() const {
        return _data;
    }

};


size_t MyString::DCtor = 0;
size_t MyString::Ctor = 0;
size_t MyString::CCtor = 0;
size_t MyString::CAsgn = 0;
size_t MyString::MCtor = 0;
size_t MyString::MAsgn = 0;
size_t MyString::Dtor = 0;

size_t MyStrNoMove::DCtor = 0;
size_t MyStrNoMove::Ctor = 0;
size_t MyStrNoMove::CCtor = 0;
size_t MyStrNoMove::CAsgn = 0;
size_t MyStrNoMove::MCtor = 0;
size_t MyStrNoMove::MAsgn = 0;
size_t MyStrNoMove::Dtor = 0;


namespace std {
    template<>
    struct hash<MyString> {
        size_t operator() (const MyString& s) const noexcept {
            return hash<string>() (string( s.get() ));
        }
    };

    template<>
    struct hash<MyStrNoMove> {
        size_t operator() (const MyStrNoMove& s) const noexcept {
            return hash<string>() (string( s.get() ));
        }
    };
};

template<typename T>
void output_static_data(const T& myStr) {
    cout<< typeid(myStr).name()<<"--"<<endl;
    cout<<"CCtor = " <<T::CCtor << " MCtor = " << T::MCtor <<" CAsgn = "<<T::CAsgn<<" MAsgn = "<<T::MAsgn;
    cout<< " Dtor = "<< T::Dtor<< " Ctor = "<< T::Ctor<<" DCtor = "<<T::DCtor<< endl;
}

template<typename M, typename N>
void test_movable(M c1, N c2, long& val) {
    char buf[10];
    //test Move
    cout<<"test with movable elements"<<endl;
    typedef typename iterator_traits<typename M::iterator>::value_type V1type;
    clock_t timeStart = clock();
    for(long i = 0; i < val; ++i) {
        snprintf(buf, 10, "%d", rand());
        auto ite = c1.end();
/* 如果这样调用 -> 不是临时对象 -> 不会调用MCtor
V1type item(buf);
c1.insert(ite, item); 
*/
        c1.insert(ite, V1type((buf)));// V1type(buf) 是一个临时对象 -> 调用Ctor
    }
    cout<<"construction milli-seconds:  "<<(clock() - timeStart)<<endl;
    cout<<"size()= "<<c1.size()<<endl;
    output_static_data(*(c1.begin()));

    clock_t copytime = clock();
    M c11(c1);
    cout<<"copy, milli-seconds:  "<<(clock() - copytime)<<endl;

    clock_t movetime = clock();
    M c12(move(c1));
    cout<<"move, milli-seconds:  "<<(clock() - movetime)<<endl;
    
    clock_t swaptime = clock();
    c11.swap(c12);
    cout<<"swap, milli-seconds:  "<<(clock() - swaptime)<<endl;

    cout<<"-----------------------------------"<<endl;
    cout<<"test with nomovable elements"<<endl;
    //test noMove
    typedef typename iterator_traits<typename N::iterator>::value_type V2type;
    clock_t timeStart2 = clock();
    for(long i = 0; i < val; ++i) {
        snprintf(buf, 10, "%d", rand());
        auto ite = c2.end();
        c2.insert(ite, V2type(buf));
    }

    cout<<"construction milli-seconds:  "<<(clock() - timeStart2)<<endl;
    cout<<"size()= "<<c2.size()<<endl;
    output_static_data(*(c2.begin()));

        clock_t copytime1 = clock();
    N c21(c2);
    cout<<"copy, milli-seconds:  "<<(clock() - copytime1)<<endl;

    clock_t movetime1 = clock();
    N c22(move(c2));
    cout<<"move, milli-seconds:  "<<(clock() - movetime1)<<endl;
    
    clock_t swaptime1 = clock();
    c21.swap(c22);
    cout<<"swap, milli-seconds:  "<<(clock() - swaptime1)<<endl;

}

int main(int argc, const char* argv[]) {
    long val = 3000000;  
    // test_movable(vector<MyString>(), vector<MyStrNoMove>(), val);
    test_movable(list<MyString>(), list<MyStrNoMove>(), val);
    // test_movable(deque<MyString>(), deque<MyStrNoMove>(), val);
    return 0;
}